//--------------------------------------------------------------------------------------
// File: EmptyProject10.cpp
//
// Empty starting point for new Direct3D 9 and/or Direct3D 10 applications
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#pragma warning(disable: 4312)

#include "atlbase.h"
#include "DXUT.h"
#include "SDKmisc.h"
#include "Dxutcamera.h"
#include "Camera.h"
#include "Sky.h"
//#include "Ocean.h"
CCamera V;
Sky * s;
//Ocean * o;
CFirstPersonCamera                  g_Camera;               // A model viewing camera
bool                                g_bLeftButtonDown = false;
bool                                g_bRightButtonDown = false;
bool                                g_bMiddleButtonDown = false;
bool								bStartRecord = false;

ID3DX10Font*                        g_pFont10 = NULL;
ID3DX10Sprite*                      g_pSprite10 = NULL;
CDXUTTextHelper*                    g_pTxtHelper = NULL;
void RenderTextInfo();
//--------------------------------------------------------------------------------------
// Reject any D3D10 devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D10DeviceAcceptable( UINT Adapter, UINT Output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    return true;
}

//--------------------------------------------------------------------------------------
// Called right before creating a D3D9 or D3D10 device, allowing the app to modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
	pDeviceSettings->d3d10.sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	pDeviceSettings->d3d10.SyncInterval = 0;
    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3D10 resources that aren't dependant on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
	s = new Sky( pd3dDevice );
	D3DXVECTOR3 vPt(0,10,0);
	D3DXVECTOR3 vLookat(0,20,0);
	g_Camera.SetViewParams(&vPt,&vLookat);    
	g_Camera.SetRotateButtons( true, false, false );
	g_Camera.SetScalers( 0.01f, 10.0f );
    //g_Camera.SetDrag( true );
    //g_Camera.SetEnableYAxisMovement( true );
	//D3DXVECTOR3 vMin = D3DXVECTOR3( -10000.0f, -10000.0f, -10000.0f );
	//D3DXVECTOR3 vMax = D3DXVECTOR3( 10000.0f, 10000.0f, 10000.0f );
	//g_Camera.SetClipToBoundary( TRUE, &vMin, &vMax );
    //g_Camera.FrameMove( 0 );
	//V.setPos(D3DXVECTOR3(0,10,0));

	V_RETURN( D3DX10CreateFont( pd3dDevice, 35, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
                                OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
                                L"Arial", &g_pFont10 ) );
    V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite10 ) );
	g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont10, g_pSprite10, 35 );

	//s->SetSunTime( 0.5 );
    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3D10 resources that depend on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D10ResizedSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
	g_Camera.SetProjParams(D3DX_PI/4, 4.0f/3.0f, 1.0f, 10000.0f);
    return S_OK;
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
bool Done = false;
bool bUpdateSun = true;
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
	s->SetSunTime(fTime * 0.025);
	//if( Done )
	//{
		//o->SetTime( fTime );
		//Done = !Done;
	//}
	if(bUpdateSun)
	{
		//V.UpdateCamera( fElapsedTime );
		//V.Update();
		g_Camera.FrameMove(fElapsedTime);
	}
	//s->SetSunTime( 0.5 );

	//Done = !Done;
 }

void RenderTextInfo()
{
	g_pTxtHelper->Begin();
    g_pTxtHelper->SetInsertionPos( 2, 0 );
    g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
    V(g_pTxtHelper->DrawTextLine( DXUTGetFPSStr( DXUTIsVsyncEnabled()) ));
    //V(g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ));
	/*WCHAR tmp[255];
	memset(tmp,0,sizeof(WCHAR)*255);
	swprintf_s(tmp,L"(%f,%f,%f)",g_Camera.GetEyePt()->x,g_Camera.GetEyePt()->y
		,g_Camera.GetEyePt()->z);
	g_pTxtHelper->DrawTextLine(tmp);*/
	g_pTxtHelper->End();
}


//--------------------------------------------------------------------------------------
// Render the scene using the D3D10 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    // Clear render target and the depth stencil 
    float ClearColor[4] = { 0, 50.0f/255.0f, 100.0f/255.0f, 1.0f };

    pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), ClearColor );
    pd3dDevice->ClearDepthStencilView( DXUTGetD3D10DepthStencilView(), D3D10_CLEAR_DEPTH, 1.0, 0 );

	// Sky
	//s->Render( *(V.getViewMatrix()), *(V.getProjectionMatrix()) );
	s->Render( *(g_Camera.GetViewMatrix()), *(g_Camera.GetProjMatrix()) );
	RenderTextInfo();

	if(bStartRecord)
	{
		static UINT s_FrameNumber = 0;
		++s_FrameNumber;
		WCHAR wcFilename[512];
		StringCchPrintf( wcFilename, 512, L"%s\\Frame%.4d.jpg", L".\\", s_FrameNumber );
		OutputDebugString( L"Saving frame as '" );
		OutputDebugString( wcFilename );
		OutputDebugString( L"'...\n" );
// Extract the actual back buffer
		CComPtr<ID3D10Texture2D> pBackBuffer;
		DXUTGetDXGISwapChain()->GetBuffer( 0, __uuidof( ID3D10Texture2D ), reinterpret_cast< void** >( &pBackBuffer ) );

		// Save the backbuffer directly
		if( FAILED( D3DX10SaveTextureToFile( pBackBuffer, D3DX10_IFF_JPG , wcFilename ) ) )
		{
			OutputDebugString( L"Unable to save back-buffer texture to file!" );
			return;
		}
	}

}


//--------------------------------------------------------------------------------------
// Release D3D10 resources created in OnD3D10ResizedSwapChain 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext )
{

}


//--------------------------------------------------------------------------------------
// Release D3D10 resources created in OnD3D10CreateDevice 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D10DestroyDevice( void* pUserContext )
{
	SAFE_DELETE( g_pTxtHelper );
    SAFE_RELEASE( g_pFont10 );
    SAFE_RELEASE( g_pSprite10 );
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
	// Pass all remaining windows messages to camera so it can respond to user input
    g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
    return 0;
}


//--------------------------------------------------------------------------------------
// Handle key presses
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
	if( bKeyDown )
    {
        switch( nChar )
        {
            case VK_F4:
                bUpdateSun = !bUpdateSun; 
				break;

			case VK_F7:
				bStartRecord = !bStartRecord;
				break;
        }
    }
}


//--------------------------------------------------------------------------------------
// Handle mouse button presses
//--------------------------------------------------------------------------------------
void CALLBACK OnMouse( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, 
                       bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, 
                       int xPos, int yPos, void* pUserContext )
{
	bool bOldLeftButtonDown = g_bLeftButtonDown;
    bool bOldRightButtonDown = g_bRightButtonDown;
    bool bOldMiddleButtonDown = g_bMiddleButtonDown;
    g_bLeftButtonDown = bLeftButtonDown;
    g_bMiddleButtonDown = bMiddleButtonDown;
    g_bRightButtonDown = bRightButtonDown;

    if( bOldLeftButtonDown && !g_bLeftButtonDown )
        g_Camera.SetEnablePositionMovement( false );
    else if( !bOldLeftButtonDown && g_bLeftButtonDown )
        g_Camera.SetEnablePositionMovement( true );

	
    // If no mouse button is down at all, enable camera movement.
    if( !g_bLeftButtonDown && !g_bRightButtonDown && !g_bMiddleButtonDown )
        g_Camera.SetEnablePositionMovement( true );
}


//--------------------------------------------------------------------------------------
// Call if device was removed.  Return true to find a new device, false to quit
//--------------------------------------------------------------------------------------
bool CALLBACK OnDeviceRemoved( void* pUserContext )
{
    return true;
}


//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // DXUT will create and use the best device (either D3D9 or D3D10) 
    // that is available on the system depending on which D3D callbacks are set below

    // Set general DXUT callbacks
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackKeyboard( OnKeyboard );
    DXUTSetCallbackMouse( OnMouse );
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
    DXUTSetCallbackDeviceRemoved( OnDeviceRemoved );

    // Set the D3D10 DXUT callbacks. Remove these sets if the app doesn't need to support D3D10
    DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable );
    DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice );
    DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizedSwapChain );
    DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender );
    DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain );
    DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice );

    // Perform any application-level initialization here
    
    DXUTInit( true, true, NULL ); // Parse the command line, show msgboxes on error, no extra command line params
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"SkyRendering" );
    DXUTCreateDevice( true, 800, 600);  
    DXUTMainLoop(); // Enter into the DXUT render loop
	D3DX10UnsetAllDeviceObjects( DXUTGetD3D10Device() );

    // Perform any application-level cleanup here
	delete s;
	//delete o;
    return DXUTGetExitCode();
}
